package segimasat.partition.floating;


import java.util.ArrayList;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.PriorityQueue;
import segimasat.image.Image;
import segimasat.image.Image32;
import segimasat.pixel.floating.*;
import segimasat.image.integer.RGB;
import segimasat.image.integer.StackRGB;
import segimasat.partition.Neighborhood;
import segimasat.pixel.PixelSum;
import segimasat.pixel.integer.PixelValue8;


public class Partition32 extends segimasat.partition.Partition{
    public Image32 f;

    public Partition32(Image f, int alpha, int omega, double ci){
        this.f = (Image32)f;
        this.alpha = alpha;
        this.omega = omega;
        this.ci = ci;
        String tittle = "ALPHA = " + alpha + ", OMEGA = " + omega;
        if (f.impl.getStackSize() == 1){
            this.out = new RGB(f.impr.getWidth(), f.impr.getHeight(), tittle);
        }
        else if (f.impl.getStackSize() > 1){
            this.out = new StackRGB(f.impr.getWidth(), f.impr.getHeight(), f.impl.getStackSize(), tittle);
        }
    }

    public void makeRegions(){
        Neighborhood nbh = new Neighborhood(f.impr.getWidth(), f.impr.getHeight());
        int n = f.impr.getHeight() * f.impr.getWidth();
        PriorityQueue<PixelPriority32> PQueue = new PriorityQueue<PixelPriority32>();
        components = new ArrayList<Component32>();
        lbl = new int[n];
        float[] rl = new float[n];
        int lblval = 0;
        for (int i = 0; i < n; i++){
            lbl[i] = -1;
            rl[i] = Integer.MAX_VALUE;
        }
        for (int p = 0; p < n; p++){
            if (lbl[p] == -1){
                PixelSum lblColor = f.newPixelFloat();
                LinkedList<Integer> stack = new LinkedList<Integer>();
                ListIterator<Integer> it = stack.listIterator();
                PixelValue32 mincc = f.getPixel(p);
                PixelValue32 maxcc = f.getPixel(p);
                float rlcrt = alpha;
                float rcrt = 0;
                int edges = 0;
                int edgesOK = 0;
                PQueue.add(new PixelPriority32(p, 0));
                while (! PQueue.isEmpty()){
                    PixelPriority32 datum = PQueue.remove();
                    // Añadido al algoritmo original: si el pixel ya fue visitado, no lo vuelve a visitar
                    if (rl[datum.p] == -1)
                        continue;
                    if (lbl[datum.p] != -1)
                        continue;
                    if (datum.prio > rcrt){
                        while (it.hasPrevious()){
                            int r = it.previous();
                            lbl[r] = lblval;
                            lblColor.add(f.getPixel(r));
                        }
                        rcrt = datum.prio;
                        if (lbl[datum.p] != -1)
                            continue;
                    }
                    it.add(datum.p);
                    // Añadido al algoritmo original: el pixel se pone a -1 en rl, para que no lo visite mas
                    rl[datum.p] = -1;
                    PixelValue32 fp = f.getPixel(datum.p);
                    mincc.checkIsLowerThan(fp);
                    maxcc.checkIsGreaterThan(fp);
                    if (omega < maxcc.rangeNoAbs(mincc) || (rcrt > rlcrt)){
                        while (! PQueue.isEmpty())
                            rl[PQueue.remove().p] = Integer.MAX_VALUE;
                        while(it.hasPrevious()){
                            rl[it.previous()] = Integer.MAX_VALUE;
                            it.remove();
                        }
                        break;
                    }
                    for (int z = 0; z < Neighborhood.NEIGHBORS; z++){
                        Integer q = nbh.getNeighbor(datum.p, z);
                        if (q == null) continue; // No hay vecino, está en un borde de la imagen.
                        float rlval = f.getPixel(q).range(f.getPixel(datum.p));
                        if ((lbl[q] != -1) && (lbl[q] != lblval) && (rlcrt >= rlval)){
                            //rlcrt = rlval; // Esto es segun el algoritmo original, pero 99% seguro que esta mal
                            rlcrt = rlval - 1; //
                            if (rcrt > rlcrt){
                                while (! PQueue.isEmpty())
                                    rl[PQueue.remove().p] = Integer.MAX_VALUE;
                                while(it.hasPrevious()){
                                    rl[it.previous()] = Integer.MAX_VALUE;
                                    it.remove();
                                }
                                break;
                            }
                        }
                        else if ((rlval <= rlcrt) && (rlval < rl[q])){
                            rl[q] = rlval;
                            PQueue.add(new PixelPriority32(q, rlval));
                        }
                    }
                } // Fin del while
                while (it.hasPrevious()){
                    int r = it.previous();
                    lbl[r] = lblval;
                    lblColor.add(f.getPixel(r));
                }
                lblval++;

                Component32 comp = new Component32(stack, lblColor, rcrt);
                components.add(comp);
                colourComponent(comp);
            }
        }
    }

    public void colourComponentFirstTime(segimasat.partition.Component comp){
        ListIterator<Integer> it = comp.pixels.listIterator();
        PixelValue32 mincc = f.newPixelValue(Integer.MAX_VALUE);
        PixelValue32 maxcc = f.newPixelValue(0);
        while (it.hasNext()){
            int p = it.next();
            out.putPixel(p, ((Component32)comp).color.getRGB());
            PixelValue32 fp = f.getPixel(p);
            mincc.checkIsLowerThan(fp);
            maxcc.checkIsGreaterThan(fp);
        }
        out.impl.updateAndDraw();
        ((Component32)comp).min = mincc;
        ((Component32)comp).max = maxcc;
    }

    public void colourComponent(segimasat.partition.Component comp){
        ListIterator<Integer> it = comp.pixels.listIterator();
        while (it.hasNext()){
            int p = it.next();
            out.putPixel(p, ((Component32)comp).color.getRGB());
        }
        out.impl.updateAndDraw();
    }

    public void colourComponent(segimasat.partition.Component comp, Object color){
        ListIterator<Integer> it = comp.pixels.listIterator();
        while (it.hasNext()){
            int p = it.next();
            out.putPixel(p, ((PixelValue8)color).getRGB());
        }
        out.impl.updateAndDraw();
    }



    @Override
    public String getColorString(int pixel) {
        throw new UnsupportedOperationException("Not supported yet.");
    }
}